﻿using FreesenseSubAIS.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using NLog;
using ExternControlModel;

namespace FreesenseSubAIS.SocketModel
{
    #region 结构体
    /// <summary>
    /// 通信数据
    /// </summary>
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct ComData
    {
        public int cmdID; //命令指令
        //public int pcID; //pc指令
        //public int camID; //相机指令
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]//定义数组长度;4*16
        public int[] iData;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]//定义数组长度;8*16
        public double[] dData;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]//定义数组长度;
        public char[] cData;
        public int quit; //中断信号
        public int result; //用于返回最终的检测结果

        public ComData(int _cmdID)
        {
            cmdID = _cmdID;
            iData = new int[16];
            dData = new double[16];
            cData = new char[256];
            quit = 0;
            result = 0;
        }
    }
    #endregion
    delegate bool ShotByIndexEventHandle(int index);
    delegate bool BoolEventHandle();
    delegate bool BoolChangeProductEventHandle(string productname);
    delegate int IntEventHandle();
    delegate MarkResult MarkResultEventHandle();
    delegate ResultInfo ResultInfoEventHandle();

    public class ServerMgr : IExternControlAdapter<ResultInfo>
    {
        #region 服务器字段
        private AsyncTcpServer _tcpServer = null;
        private string _localIp = "127.0.0.1";
        private int _port = 888;

        private Thread recvDataThrd = null;
        CancellationTokenSource recvDataCts = null;
        object recvObj = new object();
        public Queue<ComData> comDataQueue = new Queue<ComData>();
        public int comDQLength = 100;                           //指令集队列长度上限
        private static ILogger _Log;
        #endregion

        #region 构造器
        public ServerMgr()
            : this("127.0.0.1", 888)
        {
        }

        public ServerMgr(string ip, int port)
        {
            this._localIp = ip;
            this._port = port;
            _Log = LogManager.GetLogger("tcp");
        }
        #endregion

        #region 资源管理
        public bool open()
        {
            try
            {
                //开启服务器
                this._tcpServer = new AsyncTcpServer(this._localIp, this._port, (new ComData()).GetType());
                this._tcpServer.Encoding = Encoding.UTF8;
                this._tcpServer.ClientConnected +=
                              new EventHandler<TcpClientConnectedEventArgs>(server_ClientConnected);
                this._tcpServer.ClientDisconnected +=
                  new EventHandler<TcpClientDisconnectedEventArgs>(server_ClientDisconnected);
                //this._tcpServer.PlaintextReceived +=
                //  new EventHandler<TcpDatagramReceivedEventArgs<string>>(server_PlaintextReceived);
                this._tcpServer.Start();
                //this._tcpServer.TcpServerStart();

                //启动侦听线程
                this.recvDataCts = new CancellationTokenSource();
                this.recvDataThrd = new Thread(new ThreadStart(this.RecvDataFunc));
                this.recvDataThrd.IsBackground = true;
                this.recvDataThrd.Start();
                Device.DeviceEntityControl.OnlineS = DeviceStatusEnum.Unknow;
                Device.DeviceEntityControl.OnlineMsg = "服务已开启，等待主机客户端连接";
                return true;
            }
            catch (Exception ex)
            {
                var msg = string.Format("从机未开机，请开启运动控制电脑，并检查网络连接\n{0}", ex.Message);
                Device.DeviceEntityControl.OnlineMsg = msg;
                Device.DeviceEntityControl.OnlineS = DeviceStatusEnum.UnNormal;
                //System.Windows.Forms.MessageBox.Show(msg, "警告", System.Windows.Forms.MessageBoxButtons.OK
                   //, System.Windows.Forms.MessageBoxIcon.Hand);
                return false;
            }
        }

        void server_ClientConnected(object sender, TcpClientConnectedEventArgs e)
        {
            Device.DeviceEntityControl.OnlineMsg = string.Format("客户端已连接{0}", e.TcpClient.Client.RemoteEndPoint.ToString());
            Device.DeviceEntityControl.OnlineS = DeviceStatusEnum.Normal;
            _Log.Info(string.Format("客户端已建立连接：{0}", e.TcpClient.Client.RemoteEndPoint.ToString()));
        }

        void server_ClientDisconnected(object sender, TcpClientDisconnectedEventArgs e)
        {
            Device.DeviceEntityControl.OnlineMsg = string.Format("客户端已断开连接{0}", e.TcpClient.Client.RemoteEndPoint.ToString());
            Device.DeviceEntityControl.OnlineS = DeviceStatusEnum.Unknow;
            _Log.Info(string.Format("客户端已断开连接：{0}", e.TcpClient.Client.RemoteEndPoint.ToString()));
        }

        static void server_PlaintextReceived(object sender, TcpDatagramReceivedEventArgs<string> e)
        {
            //if (e.Datagram != "Received")
            //{
            //    Console.Write(string.Format("Client : {0} --> ",
            //      e.TcpClient.Client.RemoteEndPoint.ToString()));
            //    Console.WriteLine(string.Format("{0}", e.Datagram));
            //    server.Send(e.TcpClient, "Server has received you text : " + e.Datagram);
            //}
        }

        public void close()
        {
            //关闭侦听线程
            this.recvDataCts.Cancel();

            //关闭服务器
            //this._tcpServer.CloseAll();
            this._tcpServer.Dispose();

            //清空数据缓存
            this.comDataQueue.Clear();
        }
        #endregion

        #region 回调定义
        internal event Action ShotSingleTask;//单独拍照
        internal event Action ShotContinueTask;//连续拍照
        internal event Action StopShotTask;//停止拍照
        internal event BoolEventHandle GetCamaerStateTask;//查询相机状态
        internal event Action ShotMarkTask;//产品定位

        internal event MarkResultEventHandle QueryMarkResult;//产品定位结果,马上返回
        internal event Action ShotDustupTask;//上清灰
        internal event Action ShotDustdownTask;//下清灰
        internal event Action ShotVisiualTask;//目测
        internal event ShotByIndexEventHandle ShotElectricTask;//电测
        internal event ResultInfoEventHandle QueryInspResult;//测试结果,马上返回
        internal event BoolChangeProductEventHandle ChangProduct;//切换型号
        internal event IntEventHandle QuerPicCount;//查询切图数量
        public event Action<string> StartTask;//触发检测
        public event Action<int> RequestDust;
        public event Action<int> RequestVisiual;
        public event Action<int> RequestFrame;
        public event Func<ResultInfo> BackResult;
        public event Func<string, bool> ChangeOver;
        #endregion

        #region 指令解析线程
        //指令集解析线程
        private void RecvDataFunc()
        {
            try
            {
                while (true)
                {
                    if (recvDataCts.Token.IsCancellationRequested)
                        return;

                    //线程锁
                    lock (recvObj)
                    {
                        if (comDataQueue.Count < 1)
                            continue;
                    }

                    //查询指令队列对首
                    ComData _comData = comDataQueue.Peek();
                    //ComData _resultData = new ComData(_comData.cmdID);
                    int cmdID = _comData.cmdID;
                    //string _resultMsg = "";
                    //根据指令,执行每个操作；这里在每个case下生成对应的函数，如case 1001与函数Function_1001对应；
                    //_Log.Trace(string.Format("接收到指令：{0}", _comData.cmdID));
                    // 错误命令
                    if (cmdID == 0)
                    {
                        //_Log.Error(string.Format("接收到错误指令：{0},当前从机序号{1},位置0(==0)", cmdID, Device.Parameter.Subindex));
                    }
                    // 相机控制命令
                    else if (cmdID < 100)
                    {
                        int id = cmdID - (Device.Parameter.Subindex - 1) * 10;
                        switch (id)
                        {
                            case 4: //单独拍照
                                Function_0004(_comData);
                                break;
                            case 1://连续拍照
                                Function_0001(_comData);
                                break;
                            case 2://停止拍照
                                Function_0002(_comData);
                                break;
                            case 3://查询相机状态
                                Function_0003(_comData);
                                break;
                            case 5://开始检测
                                Function_0005(_comData);
                                break;
                            default:
                                //_resultData.iData[0] = -1;
                                _Log.Error(string.Format("接收到未定义指令：{0},当前从机序号{1},位置1(<100)", cmdID, Device.Parameter.Subindex));
                                break;
                        }
                    }
                    // 图像检测命令
                    else if (cmdID > 100 && cmdID < 300)
                    {
                        int id = cmdID - (Device.Parameter.Subindex - 1) * 20;

                        switch (id)
                        {
                            case 101://产品定位
                                Function_0101(_comData);
                                break;
                            case 102://产品定位结果,马上返回
                                Function_0102(_comData);
                                break;
                            case 103://上清灰
                                Function_0103(_comData);
                                break;
                            case 104://下清灰
                                Function_0104(_comData);
                                break;
                            case 105://目测
                                Function_0105(_comData);
                                break;
                            case 106://电测
                                Function_0106(_comData);
                                break;
                            case 107://测试结果,马上返回
                                Function_0107(_comData);
                                break;
                            default:
                                //_resultData.iData[0] = -1;
                                _Log.Error(string.Format("接收到未定义指令：{0},当前从机序号{1},位置2(100< <300)", cmdID, Device.Parameter.Subindex));
                                break;
                        }
                    }
                    // 产品管理命令
                    else if (cmdID >= 300)
                    {
                        int id = cmdID - (Device.Parameter.Subindex - 1) * 10;

                        switch (id)
                        {
                            case 300://切换生产产品
                                Function_0300(_comData);
                                break;
                            case 301://查询
                                Function_0301(_comData);
                                break;
                            default:
                                //_resultData.iData[0] = -1;
                                _Log.Error(string.Format("接收到未定义指令：{0},当前从机序号{1},位置3(>=300)", cmdID, Device.Parameter.Subindex));
                                break;
                        }
                    }
                    else
                    {
                        //_resultData.iData[0] = -1;
                        _Log.Error(string.Format("接收到未定义指令：{0},当前从机序号{1},位置4", cmdID, Device.Parameter.Subindex));
                    }

                    //_resultData.result = 0;
                    //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
                    //if (_resultData.iData[0] == 0)
                    //    _Log.Error(string.Format("发现iData[0]=0，当前命令为{0}，当前从机序号{1}", _comData.cmdID, Device.Parameter.Subindex));
                    //this._tcpServer.SendMessage(_resultData);

                    if (comDataQueue.Count > 0)
                        comDataQueue.Dequeue();

                    Thread.Sleep(50);
                }


            }
            catch (Exception ex)
            {
                _Log.Error("Socket消息处理出错：" + ex.Message);
                Console.WriteLine("Error" + ex.Message);
            }
        }
        #endregion

        #region 相机控制命令
        private void Function_0004(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";

            if (ShotSingleTask != null) ShotSingleTask();
            _resultData.result = 0;

            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }
        private void Function_0005(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string id = (new string(_comData.cData)).TrimEnd('\0');
            string _resultMsg = "";
            _Log.Trace("接收到开始检测指令,ID:{0}", id);
            if (StartTask != null) StartTask(id);
            _resultData.result = 0;
            _Log.Info("开始检测指令返回,ID:{0}", id);
            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }
        private void Function_0001(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";

            ShotContinueTask();
            _resultData.result = 0;

            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }

        private void Function_0002(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";

            StopShotTask();
            _resultData.result = 0;

            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }

        private void Function_0003(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";

            _resultData.iData[0] = GetCamaerStateTask() ? 0 : -1;
            _resultData.result = 0;

            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }
        #endregion

        #region 图像检测命令
        private void Function_0101(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";

            _Log.Trace("接收到定位图指令");
            ShotMarkTask();
            _resultData.result = 0;
            _Log.Trace("定位图指令返回");
            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            _tcpServer.SendMessage(_resultData);
        }

        private void Function_0102(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";

            var m = QueryMarkResult();
            switch (m.MarkRlt)
            {
                case ItemResult.none:
                    _resultData.iData[0] = -2;
                    break;
                case ItemResult.failed:
                    _Log.Trace("定位结果返回：NG");
                    _resultData.iData[0] = -1;
                    break;
                case ItemResult.pass:
                    _Log.Trace(string.Format("定位结果返回：OK，偏移量x{0},y{1},ang{2}", m.Offset.col, m.Offset.row, m.Offset.angle));
                    _resultData.iData[0] = 0;
                    _resultData.dData[0] = m.Offset.col;
                    _resultData.dData[1] = m.Offset.row;
                    _resultData.dData[2] = m.Offset.angle;
                    break;
            }

            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }

        private void Function_0103(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";

            _Log.Trace("接收到上清灰指令");
            RequestDust(-3);
            _resultData.result = 0;
            _resultData.iData[0] = 1;
            _Log.Trace("上清灰指令返回");
            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }

        private void Function_0104(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";

            _Log.Trace("接收到下清灰指令");
            RequestDust(-2);
            _resultData.result = 0;
            _resultData.iData[0] = 1;
            _Log.Trace("上清灰指令返回");
            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }

        private void Function_0105(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";

            _Log.Trace("接收到目测图指令");
            RequestVisiual(-1);
            _resultData.result = 0;
            _resultData.iData[0] = 1;
            _Log.Trace("目测图指令返回");
            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }

        private void Function_0106(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";

            _Log.Trace(string.Format("接收到电测图指令，序号：{0}", _comData.iData[0]));
            if (RequestFrame != null) RequestFrame(_comData.iData[0]);
            _resultData.result = 0;
            _resultData.iData[0] = _comData.iData[0];
            _Log.Info("接收电测图指令，结果为{0}", _resultData.iData[0]);
            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }

        private void Function_0107(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";

            var rs = BackResult();
            switch (rs.result)
            {
                case ItemResult.none:
                    _resultData.iData[0] = -2;
                    break;
                case ItemResult.failed:
                    _resultData.iData[0] = -1;
                    _resultData.iData[1] = rs.Flagindex;
                    if (rs.Sortlist != null && rs.Sortlist.Count > 0)
                        for (int i = 0; i < rs.Sortlist.Count; i++)
                            _resultData.iData[i + 2] = rs.Sortlist[i];
                    _Log.Info("检测结果返回：NG");
                    _Log.Trace(string.Format("是否点图异常：{0},NG类型数量：{1}", rs.Flagindex, rs.Sortlist.Count));
                    break;
                case ItemResult.pass:
                    _Log.Info("检测结果返回：OK");
                    _resultData.iData[0] = 0;
                    break;
            }

            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }
        #endregion

        #region 产品管理命令
        private void Function_0300(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";
            var proname = (new string(_comData.cData)).TrimEnd('\0');
            if (ChangeOver != null && ChangeOver(proname))
                _resultData.result = 0;
            else
                _resultData.result = -1;

            //_resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }

        private void Function_0301(ComData _comData)
        {
            ComData _resultData = new ComData(_comData.cmdID);
            string _resultMsg = "";

            _resultData.iData[0] = QuerPicCount();
            if (_resultData.iData[0] > 0)
                _resultData.result = 0;
            else
                _resultData.result = -1;
            _resultMsg = Device.defaultProduct.ProductName;

            _resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
            this._tcpServer.SendMessage(_resultData);
        }
        #endregion

        #region 字符串处理
        public static string CharToString(char[] chars)
        {
            string str = "";
            int len = 0;
            for (int i = 0; i < chars.Length; i++)
            {
                if (chars[i] == '\0')
                {
                    len = i;
                    break;
                }
            }
            string msg = new string(chars);
            str = msg.Substring(0, len);
            return str;
        }

        /// <summary>
        /// 将列表中的数据通过-号连接，并返回连接后的字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="lst"></param>
        /// <returns></returns>
        public static string GetString<T>(List<T> lst)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < lst.Count; i++)
            {
                sb.Append(lst[i]);
                if (i < lst.Count - 1)
                    sb.Append("-");
            }
            return sb.ToString();
        }
        #endregion
    }

}

